<?php

namespace Frieza\Modules\AdServing\Controllers;

use ApkParser\Parser;
use Doraemon\oss\Apk;
use Doraemon\tools\Log;
use App\Library\Common;
use Illuminate\Http\Request;
use Encore\Admin\Widgets\Tab;
use Encore\Admin\Widgets\Form;
use Encore\Admin\Facades\Admin;
use Encore\Admin\Layout\Content;
use Illuminate\Routing\Redirector;
use Illuminate\Support\MessageBag;
use Doraemon\service\DingTalkAlert;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Doraemon\model\AdServing\Serving;
use Doraemon\model\AdServing\UploadApkLog;
use Illuminate\Contracts\Foundation\Application;

/**
 * Description: 包上传
 * Created by PhpStorm.
 * User: 玉坤
 */
class UploadController extends Controller
{

    /**
     * 编辑
     *
     * @param $id
     * @param Content $content
     * @return Content|RedirectResponse
     */
    public function index(Content $content)
    {
        $baseForm = new Form();
        $baseForm->text('version', '版本号')->required()->help("例：1.1.0");
        $baseForm->largefile('apk_file', '上传app包')->rules(['apk_file' => 'mimes:apk'])->required()->help("例：hhz.apk");
        $baseForm->confirm('确定更新好好正吗？');
        $baseForm->action('/admin/adServing/upload/save');

        $tab = new Tab();
        $tab->addLink("灰度Apk上传", "/admin/adServing/uploadLog/show");
        $tab->addLink("App上传记录", "/admin/adServing/uploadLog");
        $tab->add("正式Apk上传", $baseForm, true);
        return $content
            ->header('投放管理')
            ->breadcrumb(
                [
                    'text' => '投放渠道列表',
                    'url' => '/adServing/serving'
                ],
                ['text' => "Android包上传"]
            )
            ->body($tab);
    }

    /**
     * 保存
     *
     * @param Request $request
     * @return Application|RedirectResponse|Redirector
     */
    public function save(Request $request)
    {
        try {
            $params = $request->all();
            $isBeta = $params['is_beta'] ?? 0;
            $fileName = $params['apk_file'];
            $version = $params['version'];
            $verArr = explode('.', $version);
            if (!is_array($verArr)) {
                throw new \Exception("版本号不正确，请按照：*.*.* 来填写！");
            }

            foreach ($verArr as $item) {
                if (!is_numeric($item)) {
                    throw new \Exception("版本号不正确，请用数字如：1.1.0 来填写！");
                }
            }

            $rules = $this->_getRules();
            //校验参数
            $res_msg = Common::validatorRule($rules, $params);
            if ($res_msg !== true) {
                throw new \Exception($res_msg);
            }
            $ext = pathinfo($fileName, PATHINFO_EXTENSION);
            if ($ext !== 'apk') {
                throw new \Exception("上传包必须是apk文件！");
            }
            $filePath = str_replace("_", '/', $fileName);
            $file = "/data/wwwroot/g_laravel_admin_base/storage/app/aetherupload/" . $filePath;
            if (!file_exists($file)) {
                throw new \Exception('文件不存在，重新上传');
            }
            $apkParser = new Parser($file);
            $manifest = $apkParser->getManifest();
//            $apkName = $manifest->getPackageName(); //获取apk包名
//            $apkVersion = $manifest->getVersionCode(); //获取apk版本号
            $apkVersionName = $manifest->getVersionName(); //获取apk版本名称
            if ($version != $apkVersionName) {
                throw new \Exception('上传包与输入版本不一致请重新填写');
            }
            $pa['version'] = $params['version'];
            $pa['file'] = $file;
            $this->uploadOssFile($pa, $isBeta);
            $success = new MessageBag([
                'title' => '成功',
            ]);
        } catch (\Exception $e) {
            $error = new MessageBag([
                'title' => $e->getMessage(),
            ]);
            return back()->with(compact('error'))->withInput();
        }

        return redirect('/admin/adServing/serving')->with(compact('success'));
    }

    /**
     * 上传大文件到oss
     *
     * @param $params
     * @param $isBeta
     * @return void
     */
    private function uploadOssFile($params, $isBeta): void
    {
        $title = '阿里oss上传通知';
        try {
            $version = $params['version'];
            $file = $params['file'];
            $name = '安卓-正式包';
            $obj = "release/" . $version . "/hhz.apk";
            if ($isBeta) {
                $name = '安卓-beta包';
                $obj = "beta/" . $version . "/hhz.apk";
            }
            $res = Apk::uploadSetPath($file, $obj);
            if (!$res) {
                throw new \Exception('版本上传oss失败');
            }
            $data['version'] = $version;
            $data['admin_id'] = Admin::user()->id;
            $data['admin_name'] = Admin::user()->name;
//            $data['apk_type'] = $apkType === 'apk' ? 1 : 2;
            $data['is_beta'] = (int)$isBeta === 1 ? 1 : 2;
            $data['created_at'] = time();  //创建时间
            $insertRes = UploadApkLog::insert($data);
            if ($insertRes->errorCode() !== '00000') {
                throw new \Exception('写入数据库失败');
            }
            $msg = '##### 🎉' . $name . "-" . $version . '版本上传oss成功';
        } catch (\Exception $e) {
            $msg = '##### 💔' . $name . "-" . $version . $e->getMessage();
        }
        DingTalkAlert::sendMarkdownMsg(DingTalkAlert::CHANNEL_APK, $title, $msg);
        Log::info('上传大文件到oss异步结果', ['params' => $params, 'mgs' => $msg]);
    }

    /**
     * 请求无人机
     *
     * @param $version
     * @param $channel
     * @param bool $batch
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private static function curlDrone($version, $channel, bool $batch = false): bool
    {

        $target = 'single';
        if ($batch) {
            $target = 'batch';
        }
        $request = [
            'channel' => $channel,
            'ver' => $version,
            'target' => $target,
        ];
        $log = ['url' => '', 'params' => $request, 'batch' => $batch, 'response' => ''];

        try {
            $config = config("urlConfig")['channel_apk'];
            $baseUrl = $config['base_url'];
            $infoUrl = $config['drone_info_url'];
            $noticeUrl = $config['drone_channel_notice'];
            $droneInfoUrl = $baseUrl . $infoUrl;
            $res = Common::guzzleRequest($droneInfoUrl, [], 'get');
            $res = json_decode($res, true);
            if (!is_array($res)) {
                throw new \Exception('响应数据错误');
            }
            $number = 0;
            foreach ($res as $info) {
                if (((string)$info['source'] === 'master') && isset($info['status']) && (string)$info['status'] === 'success') {
                    $number = $info['number'] ?: 0;
                }
            }
            if (!$number) {
                throw new \Exception('无人机响应数据错误number错误：' . $number);
            }
            $channelUrl = $baseUrl . $noticeUrl . $number . '/promote?channel=' . $channel . '&ver=' . $version . '&target=' . $target;
            $headers = [
                'Authorization' => $config['token'],
            ];
            $log['url'] = $channelUrl;
            $result = Common::guzzleRequest($channelUrl, [], 'post', [], $headers);
            $log['response'] = $result;
            Log::info("hhz_apk请求无人机记录：", $log);
            $response = json_decode($result, true);
            if (!is_array($response)) {
                throw new \Exception('响应数据错误');
            }
        } catch (\Exception $e) {
            Log::error('安卓apk通知无人机错误,版本：' . $version . '错误信息：' . $e->getMessage(), $log);
            return false;
        }
        return true;

    }


    /**
     * 表单参数校验
     *
     * @return string[]
     */
    private function _getRules(): array
    {
        return [
            'apk_file' => 'required',
            'version' => 'required',
        ];
    }

    /**
     * 批量投放
     *
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function noticeDrone()
    {
        try {
            $channels = Serving::select('code',
                ['status' => Serving::STATUS_NORMAL, 'terminal' => Serving::TERMINAL_ANDROID]) ?: [];
            $list = [];
            foreach ($channels as $channel) {
                if (!preg_match("/[\x7f-\xff]/", $channel)) {
                    $list[] = $channel;
                }
            }
            $chan = '';
            if ($list) {
                $chan = implode(',', $list);
            }
            $version = UploadApkLog::getLastVersion();
            if (!$version) {
                throw new \Exception('安卓包版本不存在！');
            }
            if (!$chan) {
                throw new \Exception('生产渠道码，并未建立！');
            }
            $res = self::curlDrone($version, $chan, true);
            if (!$res) {
                throw new \Exception('调用无人机失败！');
            }
            $success = [
                'title' => "Android" . $version . "版本渠道包正在生成中，请稍后刷新查看或关注群内通知",
                'code' => 1,
            ];
        } catch (\Exception $e) {
            $success = [
                'title' => '操作失败,请重试！' . $e->getMessage(),
                'code' => 0,
            ];
        }
        return response()->json($success);
    }

    /**
     * 单个投放
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function putOneChannel(Request $request)
    {
        try {
            $channel = $request->post('code', '');
            if (!$channel) {
                throw new \Exception('非法提交！');
            }
            if (preg_match("/[\x7f-\xff]/", $channel)) {
                throw new \Exception('渠道编码,不许包含中文！');
            }
            $version = UploadApkLog::getLastVersion();
            if (!$version) {
                throw new \Exception('安卓包版本不存在！');
            }

            $res = self::curlDrone($version, $channel);
            if (!$res) {
                throw new \Exception('调用无人机失败！');
            }
            $success = [
                'title' => "正在生成:🎉 Android" . $version . " 版本 " . $channel . " 渠道包,请稍后刷新查看或关注群内通知",
                'code' => 1,
            ];
        } catch (\Exception $e) {
            $success = [
                'title' => '操作失败,请重试！' . $e->getMessage(),
                'code' => 0,
            ];
        }
        return response()->json($success);
    }


}